24. 药品销售数据分析

药品销售数据分析的价值

医院药品销售分析可以从多个维度挖掘商业价值:

  • 库存管理:优化药品采购,避免缺货或积压
  • 处方分析:了解医生开药习惯与偏好
  • 医保分析:社保使用情况与政策影响
  • 销售预测:把握季节性需求波动规律

本章分析任务概览

本案例使用朝阳医院2018年药品销售数据,完成四大分析任务:

任务编号 分析内容 核心方法
任务1 销售最好/最差的药品 分组聚合 + 柱状图
任务2 销售额时间变化趋势 时间序列 + 折线图
任务3 各月份最佳药品 循环 + 分组统计
任务4 社保减免对购买意愿的影响 特征工程 + 频率统计

数据预处理:导入与预览

分析的第一步是导入必要的库并读取数据:

  • pandas:数据分析核心库
  • numpy:数值计算库
  • seaborn / matplotlib:可视化库
  • 使用 pd.read_excel() 读取 Excel 数据文件
  • 使用 df.shapedf.head() 预览数据结构

数据预处理:类型转换与特征提取

原始数据需要进行以下预处理操作:

  • 类型转换:将社保卡号、商品编码转为字符串类型
  • 日期提取:从购药时间中分离出日期和星期
  • 缺失值处理:使用 dropna() 删除含缺失值的行
  • 重复值检查:使用 duplicated().sum() 统计重复记录

⭐ 平台实操:药品销售数据分析完整代码

Listing 1
# 注:朝阳医院2018年销售数据.xlsx数据文件本地没有,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import pandas as pd  # 导入Pandas数据分析库
import numpy as np  # 导入NumPy数值计算库
import seaborn as sns  # 导入Seaborn可视化库
import matplotlib.pyplot as plt  # 导入Matplotlib绑图库
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置Matplotlib全局参数

#数据读取
df = pd.read_excel("朝阳医院2018年销售数据.xlsx")

#数据预览与预处理
## 查看数据维度
print(df.shape)
print(df.head())  # 输出前几行数据

## 查看数据信息  
print(df.info())

df['社保卡号']=df['社保卡号'].astype(str)  # 转换数据类型
df['商品编码']=df['商品编码'].astype(str)  # 转换数据类型
df['购药日期']=df['购药时间'].str.split(pat=' ',expand=True)[0]  # 对字符串列进行处理
df['购药星期']=df['购药时间'].str.split(pat=' ',expand=True)[1]  # 对字符串列进行处理

## 查看各列的缺失值
df.isnull().sum()

## 缺失值处理
## 直接删除
df.dropna(axis=0,inplace=True)

## 查看重复值数量
df.duplicated().sum()

#探索性数据分析
##任务1:销售情况最好的药品是?最差的药品是?
##提示:通过对药品进行分组聚合统计,在此处我们评定销售情况好的标准是销售数量总和。之后取出前n个药品进行可视化展示

df_sum=df.groupby('商品名称')['实收金额'].sum().reset_index()  # 按指定列分组聚合
print(df_sum.nlargest(2,'实收金额')) #用于获取实收金额列中最大的两个值所对应的行。
print(df_sum.nsmallest(2,'实收金额')) #用于获取实收金额列中最小的两个值所对应的行。

df_sum_n10=df_sum.nlargest(10,'实收金额')  # 筛选出排名前10的记录
plt.figure(figsize=(15,10))  # 创建图形画布
plt.grid()  # 显示网格线
plt.bar(df_sum_n10['商品名称'],df_sum_n10['实收金额'])  # 绑制柱状图
plt.savefig("1.png")  # 保存图形至文件
plt.close()  # 关闭文件或连接

#任务2:整体销售额的时间变化趋势
##数据集中存在时间数据,但是不够简洁,所以需要先对时间数据进行处理:

df["购药时间_月"] = df["购药时间"].map(lambda x:x.split(" ")[0].split("-")[1]) ##购药日期所属月份   
df["购药时间_星期"] = df["购药时间"].map(lambda x:x.split(" ")[1]) ##购药当天是星期几? 

#对时间数据处理完成之后,就可以进行时间维度上的销售情况分析,与任务1一致,评定指标也选择为销售数量之和。

# 在下方开始你的分析
df['购药日期_月']=df['购药日期'].str.split(pat='-',expand=True)[1]
plt.figure(figsize=(15,10))  # 创建图形画布
plt.grid()  # 显示网格线
sns.lineplot(x='购药日期_月',y='实收金额',data=df,estimator='sum')  # 绑制折线图
plt.savefig("2.png")  # 保存图形至文件
plt.close()  # 关闭文件或连接

plt.figure(figsize=(15,10))  # 创建图形画布
plt.grid()  # 显示网格线
sns.lineplot(x='购药星期',y='实收金额',data=df,estimator='sum')  # 绑制折线图
plt.savefig("3.png")  # 保存图形至文件
plt.close()  # 关闭文件或连接

#任务3:各月份卖的最好的药品是那些?
values1=df['购药日期_月'].unique()
values1=pd.Series(values1)  # 创建Series序列values1
for value in values1:  # 遍历values1中的每个value
    df_value=df[df['购药日期_月']==value]  # 提取购药日期_月列作为df_value变量
  df_print=df_value.groupby(['购药日期_月','商品名称'])['实收金额'].sum().nlargest(1).reset_index()  # 按指定列分组聚合
    print(df_print)  # 输出数据框数据

#任务4:人们是否会更愿意购买可使用社保减免的药品?
df['差额']=df['应收金额']-df['实收金额']
df['是否社保减免药品']=df['差额'].apply(lambda x : '是' if x!=0 else '否')  # 定义匿名函数df['是否社保减免药品']
df['是否社保减免药品'].value_counts(normalize=True)  # 统计是否社保减免药品列各取值的频率分布

#####总结
# 卖的最好的是 开博通
# 卖的最差的是 TG厄贝沙坦片
# 药品的销售数量与时间有关
# 药品的销售数量与是否使用社保有关

任务1:分析目标与方法

目标:找出销售额最高和最低的药品

核心方法

  • 使用 groupby('商品名称') 按药品分组
  • 实收金额 列调用 .sum() 求和
  • nlargest(n) 提取销售前 n 名
  • nsmallest(n) 提取销售后 n 名

任务1:分组聚合统计代码详解

Listing 2
# 按商品名称分组,计算每种药品的销售总额
df_sum = df.groupby('商品名称')['实收金额'].sum().reset_index()

# 提取销售金额最高的2种药品
print('销售最好的2种药品:')
print(df_sum.nlargest(2, '实收金额'))

# 提取销售金额最低的2种药品
print('\n销售最差的2种药品:')
print(df_sum.nsmallest(2, '实收金额'))

任务1:TOP10药品柱状图

Listing 3
# 提取销售金额TOP10的药品
df_sum_n10 = df_sum.nlargest(10, '实收金额')

plt.figure(figsize=(15, 10))
plt.bar(df_sum_n10['商品名称'], df_sum_n10['实收金额'], color='steelblue')
plt.title('销售金额TOP10药品', fontsize=16)
plt.xlabel('药品名称', fontsize=12)
plt.ylabel('销售金额(元)', fontsize=12)
plt.xticks(rotation=45, ha='right')  # 旋转标签防止重叠
plt.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()

任务1:业务洞察

分析结果揭示关键商业信息:

  • 销售冠军:开博通——医院收入支柱,需保证库存充足
  • 销售垫底:TG厄贝沙坦片——考虑促销或淘汰
  • TOP10可视化:直观展示药品销售层级差异
  • 采购策略:增加畅销品库存深度,减少滞销品积压

任务2:分析目标与方法

目标:揭示销售额的月度趋势和星期趋势

核心方法

  • 字符串分割提取月份特征:str.split('-')[1]
  • sns.lineplot() 绑制折线图
  • estimator='sum' 对每组销售额求和
  • 分别从月度和星期两个维度分析

任务2:月度销售趋势代码详解

Listing 4
# 从购药日期提取月份
df['购药日期_月'] = df['购药日期'].str.split(pat='-', expand=True)[1]

# 绑制月度销售趋势
plt.figure(figsize=(15, 10))
sns.lineplot(x='购药日期_月', y='实收金额', data=df,
             estimator='sum', errorbar=None)
plt.title('各月销售额变化趋势', fontsize=16)
plt.xlabel('月份', fontsize=12)
plt.ylabel('销售金额(元)', fontsize=12)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

任务2:星期销售趋势代码详解

Listing 5
# 绑制星期销售趋势
plt.figure(figsize=(15, 10))
sns.lineplot(x='购药星期', y='实收金额', data=df,
             estimator='sum', errorbar=None)
plt.title('各星期销售额变化趋势', fontsize=16)
plt.xlabel('星期', fontsize=12)
plt.ylabel('销售金额(元)', fontsize=12)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

任务2:时间趋势分析洞察

  • 月度规律:流感季(冬春)销售高峰,可提前备货
  • 星期规律:工作日销售通常高于周末
  • 异常检测:峰值可能对应疫情爆发或政策变动
  • 资源规划:高峰期增加药房人手,淡季推出促销

任务3:分析目标与方法

目标:找出每个月销售额最高的药品

核心方法

  • unique() 获取所有月份的唯一值
  • for 循环遍历每个月份
  • 布尔索引筛选特定月份数据
  • groupby + nlargest(1) 找出每月冠军

任务3:各月最佳药品代码详解

Listing 6
# 获取所有月份的唯一值
months = df['购药日期_月'].unique()

for month in sorted(months):
    # 筛选该月份的销售记录
    df_month = df[df['购药日期_月'] == month]

    # 按月份和药品分组,找出销售第一名
    df_best = (df_month.groupby(['购药日期_月', '商品名称'])
               ['实收金额'].sum()
               .nlargest(1).reset_index())

    print(f'{month}月最佳药品:')
    print(df_best)
    print()

任务3:季节性用药洞察

不同季节畅销药品不同,反映疾病的季节性规律:

  • 冬春季(12-2月):感冒药、退烧药
  • 春季(3-5月):抗过敏药
  • 夏季(6-8月):消化药、防暑药
  • 秋季(9-11月):止咳药

备货策略:提前1个月备货季节性畅销品

任务4:分析目标与方法

目标:分析社保减免是否影响药品购买意愿

核心思路

  • 计算差额 = 应收金额 - 实收金额
  • 差额 ≠ 0 → 使用了社保减免
  • 差额 = 0 → 未使用社保减免
  • 统计两类的占比,判断影响程度

任务4:社保减免分析代码详解

Listing 7
# 计算应收与实收的差额
df['差额'] = df['应收金额'] - df['实收金额']

# 根据差额判断是否使用社保
df['是否社保减免药品'] = df['差额'].apply(
    lambda x: '是' if x != 0 else '否'
)

# 统计社保减免药品的占比
insurance_ratio = df['是否社保减免药品'].value_counts(normalize=True)
print('社保减免药品占比:')
print(insurance_ratio)

任务4:社保政策对购药行为的影响

  • 高占比:大部分药品使用社保减免,说明患者价格敏感
  • 医保目录:患者优先选择医保目录内药品
  • 采购策略:优先采购医保药品,保证库存充足
  • 政策敏感:医保目录调整和报销比例变化直接影响销售

本章总结

通过对朝阳医院2018年药品销售数据的分析,得出以下结论:

分析维度 关键发现
销售排名 开博通销售最好,TG厄贝沙坦片最差
时间趋势 销售额呈现明显的月度和星期波动
季节规律 不同月份畅销药品不同,反映季节性疾病
社保影响 社保减免显著提升药品购买意愿

核心技能回顾

本案例涉及的 Python 数据分析核心技能:

  • 分组聚合groupby() + sum() / count()
  • 排序筛选nlargest() / nsmallest()
  • 字符串处理str.split() 提取日期特征
  • 特征工程apply(lambda) 构造新变量
  • 可视化plt.bar() 柱状图 / sns.lineplot() 折线图